use std::fmt::Display;

use actix_session::SessionInsertError;
use actix_web::{ResponseError, http::StatusCode};
use anyhow::anyhow;

#[derive(Debug, PartialEq, PartialOrd, Clone, Copy, serde_repr::Deserialize_repr,serde_repr::Serialize_repr)]
#[repr(u8)]
pub(crate) enum Sex {
    Male=1,
    Female=2,
}

impl TryFrom<u8> for Sex {
    type Error = anyhow::Error;

    fn try_from(value: u8) -> Result<Self, Self::Error> {
        match value {
            1 => Ok(Self::Male),
            2 => Ok(Self::Female),
            _ => Err(anyhow!("Unknown sex value: {value}")),
        }
    }
}

#[derive(Debug)]
pub enum AppError {
    InternalServerError(String),
    SessionError(SessionInsertError),
    UnAuthorized(String),
}

impl From<anyhow::Error> for AppError {
    fn from(value: anyhow::Error) -> Self {
        Self::InternalServerError(value.to_string())
    }
}

impl Display for AppError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            AppError::InternalServerError(msg) => write!(f, "Internal server error: {msg}"),
            AppError::SessionError(session_insert_error) => write!(f, "{session_insert_error}"),
            AppError::UnAuthorized(msg) => write!(f, "Authorization failed, {msg}"),
        }
    }
}

impl ResponseError for AppError {
    fn status_code(&self) -> actix_web::http::StatusCode {
        match self {
            AppError::InternalServerError(_) | AppError::SessionError(_) => {
                StatusCode::INTERNAL_SERVER_ERROR
            }
            AppError::UnAuthorized(_) => StatusCode::UNAUTHORIZED,
        }
    }
}

impl From<SessionInsertError> for AppError {
    fn from(value: SessionInsertError) -> Self {
        Self::SessionError(value)
    }
}
